package com.moneywelcome.aop;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.moneywelcome.annnotation.RedisAnnotation;
import com.moneywelcome.exceptions.MwcArgsException;
import com.moneywelcome.results.StatusCode;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Slf4j
public class RedisAspect {
    @Autowired
    private StringRedisTemplate str;
    @Autowired
    private ObjectMapper om;

    @Around("@annotation(com.moneywelcome.annnotation.RedisAnnotation)")
    public Object cacheRead(ProceedingJoinPoint pjp) {
        try {
            //获得注解方法
            Method method = ((MethodSignature) pjp.getSignature()).getMethod();
            RedisAnnotation annotation = method.getAnnotation(RedisAnnotation.class);
            //判断注解对象是否为空
            if (null != annotation) {
                //判断是否是查询工作
                if (annotation.read()) {
                    log.info("查询业务");
                    //判断有没有key
                    String key;
                    if (null == annotation.value() || "".equals(annotation.value())) {
                        //没有key使用方法全限定名做key
                        key = method.getDeclaringClass().getName() + "." + method.getName();
                    } else {
                        key = annotation.value();
                    }
                    //判断redis key是否存在
                    if (str.hasKey(key)) {
                        log.info("redis拉取");
                        Class<?> type = method.getReturnType();
                        String json = str.opsForValue().get(key);
                        return om.readValue(json, type);
                    } else {
                        //redis 不存在则查询数据库并保存到redis中
                        log.info("redis存入");
                        Object obj = pjp.proceed(pjp.getArgs());
                        str.opsForValue().set(key, om.writeValueAsString(obj), annotation.expired(), TimeUnit.SECONDS);
                        return obj;
                    }
                } else {
                    //当前操作为更新操作 删除查询操作的数据的key就行
                    log.info("更新操作");
                    str.delete(Arrays.asList(annotation.refresh()));
                    return pjp.proceed(pjp.getArgs());
                }
            }
            throw new MwcArgsException("数据处理异常",StatusCode.Error);
        } catch (JsonMappingException e) {
            throw new MwcArgsException("缓存失败", e, StatusCode.Error);
        } catch (JsonProcessingException e) {
            throw new MwcArgsException("缓存失败", e, StatusCode.Error);
        } catch (Throwable throwable) {
            throw new MwcArgsException("缓存失败", StatusCode.Error);
        }
    }
}
